package com.awei.study.dataStructure.queue;

import com.awei.study.dataStructure.queue.abs.DoubleEndQueue;

import java.util.Iterator;

/**
 * @Author liweilong
 * @Date 2023/5/25 9:42
 */
public class ArrayQueue_DoubleEnd<E> implements DoubleEndQueue<E>, Iterable<E> {

    E[] array;
    int head = 0;
    int tail = 0;

    @SuppressWarnings("all")
    public ArrayQueue_DoubleEnd(int capacity) {
        this.array = (E[]) new Object[capacity + 1];
    }

    @Override
    public boolean offerHead(E value) {
        if(isFull()) return false;
        head = desc(head);
        array[head] = value;
        return true;
    }

    @Override
    public boolean offerTail(E value) {
        if(isFull()) return false;
        array[tail] = value;
        tail = incr(tail);
        return true;
    }

    @Override
    public E pollHead() {
        if(isEmpty()) return null;
        E value = array[head];
        array[head] = null;
        head = incr(head);
        return value;
    }

    @Override
    public E pollTail() {
        if(isEmpty()) return null;
        tail = desc(tail);
        E value = array[tail];
        array[tail] = null;
        return value;
    }

    @Override
    public E peekHead() {
        if(isEmpty()) return null;
        return array[head];
    }

    @Override
    public E peekTail() {
        if(isEmpty()) return null;
        return array[desc(tail)];
    }

    @Override
    public boolean isEmpty() {
        return head == tail;
    }

    @Override
    public boolean isFull() {
        if (tail > head) {
            return tail - head == array.length - 1;
        } else if (tail < head) {
            return head - tail == 1;
        } else {
            return false;
        }
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int p = head;
            @Override
            public boolean hasNext() {
                return p != tail;
            }

            @Override
            public E next() {
                E value = array[p];
                p = incr(p);
                return value;
            }
        };
    }

    private int desc(int index) {
        if (index - 1 < 0) {
            return array.length - 1;
        }
        return index - 1;
    }

    private int incr(int index) {
        if (index + 1 >= array.length) {
            return 0;
        }
        return index + 1;
    }
}
